package cn.linjianhui.cluster.service.impl;

import cn.linjianhui.cluster.dao.RedPacketDao;
import cn.linjianhui.cluster.dao.UserRedPacketDao;
import cn.linjianhui.cluster.pojo.RedPacket;
import cn.linjianhui.cluster.pojo.UserRedPacket;
import cn.linjianhui.cluster.service.RedisRedPacketService;
import cn.linjianhui.cluster.service.UserRedPacketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class UserRedPacketServiceImpl implements UserRedPacketService {

    @Autowired
    private UserRedPacketDao userRedPacketDao;

    @Autowired
    private RedPacketDao redPacketDao;

    @Autowired
    private RedisRedPacketService redisRedPacketService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final int FAILED = 0;

    @Override
    @Transactional
    public int grabRedPacket(Long redPackId, Long userId) {
        long start = System.currentTimeMillis();
        while(true) {
            long end = System.currentTimeMillis();

            if(end - start > 100) {
                return FAILED;
            }

            RedPacket redPacket = redPacketDao.getRedPacket(redPackId);

            // 加锁
//             RedPacket redPacket = redPacketDao.getRedPacketByLock(redPackId);

            // 红包库存大于0
            if (redPacket.getStock() > 0) {
                // 抢红包
//                 int update = redPacketDao.decreaseRedPacket(redPackId);

                int update = redPacketDao.decreaseRedPacketByVersion(redPackId, redPacket.getVersion());
//
//                if(update == 0) {
//                    return FAILED;
//                }

                // 没有数据更新，说明其他线程已经修改过数据，则重新抢
                if (update == 0) {
                    continue;
                }

                // 插入抢红包信息
                UserRedPacket userRedPacket = new UserRedPacket();
                userRedPacket.setUserId(userId);
                userRedPacket.setRedPacketId(redPackId);
                userRedPacket.setAmount(redPacket.getUnitAmount());
                userRedPacket.setGrabTime(LocalDateTime.now());
                return userRedPacketDao.grabRedPacket(userRedPacket);
            } else {
                return FAILED;
            }

        }
    }

    @Override
    public int grabRedPacketByRedis(Long redPackId, Long userId) {
        DefaultRedisScript<Long> grabRedPacketScript = new DefaultRedisScript<>();
        grabRedPacketScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("GrabRedPacket.lua")));
        grabRedPacketScript.setResultType(Long.class);

        // Key参数：红包编号
        List<String> keyList = new ArrayList<>();
        keyList.add(String.valueOf(redPackId));

        // Args参数：抢红包用户ID，和当前时间戳
        String args = String.format("%s-%d", userId, System.currentTimeMillis());

        Long status = redisTemplate.execute(grabRedPacketScript, keyList, args);

        // 抢红包失败
        if(ObjectUtils.isEmpty(status) || status == 0) {
            return FAILED;
        }

        // 红包已抢完，保存用户抢红包记录到数据库
        if(status == 2) {
            // 获取单个小红包金额
            Double unitAmount = Double.parseDouble((String) Objects.requireNonNull(
                    redisTemplate.opsForHash().get(String.format("red_packet_{%d}", redPackId), "unit_amount")));

            System.err.println(String.format("ThreadName = %s", Thread.currentThread().getName()));

            redisRedPacketService.saveUserRedPacketByRedis(redPackId, unitAmount);
        }

        return status.intValue();
    }
}
